Merged [14040] since it was a cute lil' one liner: Fixed a drawing glitch when the...
[adiumx.git] / Frameworks / Adium Framework / AIListCell.m
blob817927913f55865960d27a51d30cdb33c8e2d2cc
1 /* 
2  * Adium is the legal property of its developers, whose names are listed in the copyright file included
3  * with this source distribution.
4  * 
5  * This program is free software; you can redistribute it and/or modify it under the terms of the GNU
6  * General Public License as published by the Free Software Foundation; either version 2 of the License,
7  * or (at your option) any later version.
8  * 
9  * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
10  * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
11  * Public License for more details.
12  * 
13  * You should have received a copy of the GNU General Public License along with this program; if not,
14  * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
15  */
17 #import "AIListCell.h"
18 #import "AIListGroup.h"
19 #import "AIListObject.h"
20 #import "AIListOutlineView.h"
21 #import <AIUtilities/AIAttributedStringAdditions.h>
22 #import <AIUtilities/AIMutableOwnerArray.h>
23 #import <AIUtilities/AIParagraphStyleAdditions.h>
25 //#define       ORDERING_DEBUG
27 @implementation AIListCell
29 static NSMutableParagraphStyle  *leftParagraphStyleWithTruncatingTail = nil;
31 //Init
32 - (id)init
34     if((self = [super init]))
35         {
36                 topSpacing = 0;
37                 bottomSpacing = 0;
38                 topPadding = 0;
39                 bottomPadding = 0;
40                 leftPadding = 0;
41                 rightPadding = 0;
42                 leftSpacing = 0;
43                 rightSpacing = 0;
44                 
45                 font = [[NSFont systemFontOfSize:12] retain];
46                 textColor = [[NSColor blackColor] retain];
47                 invertedTextColor = [[NSColor whiteColor] retain];
48                 
49                 useAliasesAsRequested = YES;
51                 if(!leftParagraphStyleWithTruncatingTail){
52                         leftParagraphStyleWithTruncatingTail = [[NSMutableParagraphStyle styleWithAlignment:NSLeftTextAlignment
53                                                                                                                                                                   lineBreakMode:NSLineBreakByTruncatingTail] retain];
54                 }
55         }
56                 
57     return self;
60 //Copy
61 - (id)copyWithZone:(NSZone *)zone
63         AIListCell *newCell = [super copyWithZone:zone];
65         newCell->listObject = nil;
66         [newCell setListObject:listObject];
67         return(newCell);
70 //Dealloc
71 - (void)dealloc
73         [textColor release];
74         [invertedTextColor release];
75         
76         [font release];
77         
78         [listObject release];
80         [super dealloc];
83 //Set the list object being drawn
84 - (void)setListObject:(AIListObject *)inObject
86         if(inObject != listObject){
87                 [listObject release];
88                 listObject = [inObject retain];
90                 isGroup = [listObject isKindOfClass:[AIListGroup class]];
91         }
93 - (BOOL)isGroup{
94         return(isGroup);
97 //Set our control view (Better than passing this around like crazy)
98 - (void)setControlView:(AIListOutlineView *)inControlView
100         controlView = inControlView;
104 //Display options ------------------------------------------------------------------------------------------------------
105 #pragma mark Display options
106 //Font used to display label
107 - (void)setFont:(NSFont *)inFont
109         if(inFont != font){
110                 [font release];
111                 font = [inFont retain];
112         }
114         //Calculate and cache the height of this font
115         labelFontHeight = [NSAttributedString stringHeightForAttributes:[NSDictionary dictionaryWithObject:[self font] forKey:NSFontAttributeName]]; 
117 - (NSFont *)font{
118         return(font);
121 //Alignment of label text
122 - (void)setTextAlignment:(NSTextAlignment)inAlignment
124         textAlignment = inAlignment;
126 - (NSTextAlignment)textAlignment{
127         return(textAlignment);
130 //Text color
131 - (void)setTextColor:(NSColor *)inColor
133         if(inColor != textColor){
134                 [textColor release];
135                 textColor = [inColor retain];
136         }
138 - (NSColor *)textColor{
139         return(textColor);
142 - (void)setInvertedTextColor:(NSColor *)inColor
144         if(inColor != invertedTextColor){
145                 [invertedTextColor release];
146                 invertedTextColor = [inColor retain];
147         }
149 - (NSColor *)invertedTextColor{
150         return(invertedTextColor);
154 //Cell sizing and padding ----------------------------------------------------------------------------------------------
155 #pragma mark Cell sizing and padding
156 //Default cell size just contains our padding and spacing
157 - (NSSize)cellSize
159         return(NSMakeSize(0, [self topSpacing] + [self topPadding] + [self bottomPadding] + [self bottomSpacing]));
162 - (int)cellWidth
164         return([self leftSpacing] + [self leftPadding] + [self rightPadding] + [self rightSpacing]);
167 //User-defined spacing offsets.  A cell may adjust these values to to obtain a more desirable default. 
168 //These are offsets, they may be negative!  Spacing is the distance between cells (Spacing gaps are not filled).
169 - (void)setSplitVerticalSpacing:(int)inSpacing{
170         topSpacing = inSpacing / 2;
171         bottomSpacing = (inSpacing + 1) / 2;
173 - (void)setTopSpacing:(int)inSpacing{
174         topSpacing = inSpacing;
176 - (int)topSpacing{
177         return(topSpacing);
179 - (void)setBottomSpacing:(int)inSpacing{
180         bottomSpacing = inSpacing;
182 - (int)bottomSpacing{
183         return(bottomSpacing);
185 - (void)setLeftSpacing:(int)inSpacing{
186         leftSpacing = inSpacing;
188 - (int)leftSpacing{
189         return(leftSpacing);
191 - (void)setRightSpacing:(int)inSpacing{
192         rightSpacing = inSpacing;
194 - (int)rightSpacing{
195         return(rightSpacing);
198 //User-defined padding offsets.  A cell may adjust these values to to obtain a more desirable default.
199 //These are offsets, they may be negative!  Padding is the distance between cell edges and their content.
200 - (void)setSplitVerticalPadding:(int)inPadding{
201         topPadding = inPadding / 2;
202         bottomPadding = (inPadding + 1) / 2;
204 - (void)setTopPadding:(int)inPadding{
205         topPadding = inPadding;
207 - (void)setBottomPadding:(int)inPadding{
208         bottomPadding = inPadding;
210 - (int)topPadding{
211         return(topPadding);
213 - (int)bottomPadding{
214         return(bottomPadding);
216 - (void)setLeftPadding:(int)inPadding{
217         leftPadding = inPadding;
219 - (int)leftPadding{
220         return(leftPadding);
222 - (void)setRightPadding:(int)inPadding{
223         rightPadding = inPadding;
225 - (int)rightPadding{
226         return(rightPadding);
230 //Drawing --------------------------------------------------------------------------------------------------------------
231 #pragma mark Drawing
233 - (void)drawWithFrame:(NSRect)cellFrame inView:(NSView *)inControlView{
234     [self drawInteriorWithFrame:cellFrame inView:inControlView];
236 - (void)drawInteriorWithFrame:(NSRect)cellFrame inView:(NSView *)inControlView
237 {       
238         if(listObject){
239                 //Cell spacing
240                 cellFrame.origin.y += [self topSpacing];
241                 cellFrame.size.height -= [self bottomSpacing] + [self topSpacing];
242                 cellFrame.origin.x += [self leftSpacing];
243                 cellFrame.size.width -= [self rightSpacing] + [self leftSpacing];
244                 
245                 [self drawBackgroundWithFrame:cellFrame];
247                 //Padding
248                 cellFrame.origin.y += [self topPadding];
249                 cellFrame.size.height -= [self bottomPadding] + [self topPadding];
250                 cellFrame.origin.x += [self leftPadding];
251                 cellFrame.size.width -= [self rightPadding] + [self leftPadding];
253                 [self drawContentWithFrame:cellFrame];
254         }
257 //Custom highlighting (This is a private cell method we're overriding that handles selection drawing)
258 - (void)_drawHighlightWithFrame:(NSRect)cellFrame inView:(NSView *)inControlView
260         //Cell spacing
261         cellFrame.origin.y += [self topSpacing];
262         cellFrame.size.height -= [self bottomSpacing] + [self topSpacing];
263         cellFrame.origin.x += [self leftSpacing];
264         cellFrame.size.width -= [self rightSpacing] + [self leftSpacing];
265         
266         [self drawSelectionWithFrame:cellFrame];
269 //Draw Selection
270 - (void)drawSelectionWithFrame:(NSRect)rect
272         //
274         
275 //Draw the background of our cell
276 - (void)drawBackgroundWithFrame:(NSRect)rect
278         //
281 //Draw content of our cell
282 - (void)drawContentWithFrame:(NSRect)rect
284         [self drawDisplayNameWithFrame:rect];
287 //Draw our display name
288 - (NSRect)drawDisplayNameWithFrame:(NSRect)inRect
290         NSAttributedString      *displayName = [[NSAttributedString alloc] initWithString:[self labelString]
291                                                                                                                                            attributes:[self labelAttributes]];
292         NSSize                          nameSize = [displayName size];
293         NSRect                          rect = inRect;
294         
295         if(nameSize.width > rect.size.width) nameSize.width = rect.size.width;
296         if (nameSize.height > rect.size.height) nameSize.height = rect.size.height;
298         //Alignment
299         switch([self textAlignment]){
300                 case NSCenterTextAlignment:
301                         rect.origin.x += (rect.size.width - nameSize.width) / 2.0;
302                 break;
303                 case NSRightTextAlignment:
304                         rect.origin.x += (rect.size.width - nameSize.width);
305                 break;
306                 default:
307                 break;
308         }
310         //Draw (centered vertical)
311         int half = ceil((rect.size.height - labelFontHeight) / 2.0);
312         [displayName drawInRect:NSMakeRect(rect.origin.x,
313                                                                            rect.origin.y + half,
314                                                                            rect.size.width,
315                                                                            nameSize.height)];
316         [displayName release];
318         //Adjust the drawing rect
319         switch([self textAlignment]){
320                 case NSRightTextAlignment:
321                         inRect.size.width -= nameSize.width;
322                 break;
323                 case NSLeftTextAlignment:
324                         inRect.origin.x += nameSize.width;
325                         inRect.size.width -= nameSize.width;
326                 break;
327                 default:
328                 break;
329         }
330         
331         
332         return(inRect);
335 //Display string for our list object
336 - (NSString *)labelString
338         NSString *leftText = [[listObject displayArrayForKey:@"Left Text"] objectValue];
339         NSString *rightText = [[listObject displayArrayForKey:@"Right Text"] objectValue];
341         //Ordering debug
342 #ifdef ORDERING_DEBUG
343         rightText = (rightText ?
344                                  [rightText stringByAppendingFormat:@" %f",[listObject orderIndex]] :
345                                  [NSString stringWithFormat:@" %f",[listObject orderIndex]]); 
346 #endif
348         if(!leftText && !rightText){
349                 return((useAliasesAsRequested ? 
350                                 [listObject longDisplayName] :
351                                 ([listObject formattedUID] ? [listObject formattedUID] : [listObject longDisplayName])));
352         }else{
353                 //Combine left text, the object name, and right text
354                 return([NSString stringWithFormat:@"%@%@%@",
355                         (leftText ? leftText : @""),
356                         (useAliasesAsRequested ? [listObject longDisplayName] : ([listObject formattedUID] ?
357                                                                                                                                          [listObject formattedUID] :
358                                                                                                                                          [listObject longDisplayName])),
359                         (rightText ? rightText : @"")]);
360         }
363 - (void)setUseAliasesAsRequested:(BOOL)inFlag
365         useAliasesAsRequested = inFlag;
368 //Attributes for displaying the label string
369 - (NSDictionary *)labelAttributes
371         NSMutableDictionary     *labelAttributes;
372         NSDictionary            *additionalAttributes = [self additionalLabelAttributes];
373         NSColor                         *currentTextColor = ([self cellIsSelected] ? [self invertedTextColor] : [self textColor]);
375         [leftParagraphStyleWithTruncatingTail setMaximumLineHeight:(float)labelFontHeight];
377         if (additionalAttributes){
378                 labelAttributes = [NSMutableDictionary dictionaryWithObjectsAndKeys:
379                         currentTextColor, NSForegroundColorAttributeName,
380                         leftParagraphStyleWithTruncatingTail, NSParagraphStyleAttributeName,
381                         [self font], NSFontAttributeName,
382                         nil];
383                 [labelAttributes addEntriesFromDictionary:additionalAttributes];
385         }else{
386                 labelAttributes = (NSMutableDictionary *)[NSDictionary dictionaryWithObjectsAndKeys:
387                         currentTextColor, NSForegroundColorAttributeName,
388                         leftParagraphStyleWithTruncatingTail, NSParagraphStyleAttributeName,
389                         [self font], NSFontAttributeName,
390                         nil];
391         }
392         
393         return(labelAttributes);
396 //Additional attributes to apply to our label string (For Sub-Classes)
397 - (NSDictionary *)additionalLabelAttributes
399         return(nil);
402 //YES if our cell is currently selected
403 - (BOOL)cellIsSelected
405         return([self isHighlighted] &&
406                    [[controlView window] isKeyWindow] &&
407                    [[controlView window] firstResponder] == controlView);
410 //YES if a grid would be visible behind this cell (needs to be drawn)
411 - (BOOL)drawGridBehindCell
413         return(YES);
416 //The background color for this cell.  This will either be [controlView backgroundColor] or [controlView alternatingGridColor]
417 - (NSColor *)backgroundColor
419         //We could just call backgroundColorForRow: but it's best to avoid doing a rowForItem lookup if there is no grid
420         if([controlView drawsAlternatingRows]){
421                 return([controlView backgroundColorForRow:[controlView rowForItem:listObject]]);
422         }else{
423                 return([controlView backgroundColor]);
424         }
427 @end